package br.senai.sc.controller.crud;

import java.io.Serializable;
import java.util.List;
import java.util.Set;

import javax.ejb.Stateless;
import javax.inject.Inject;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.validation.ConstraintViolation;
import javax.validation.Validator;

import org.jboss.seam.international.status.Messages;
import org.jboss.seam.international.status.builder.BundleKey;

import br.senai.sc.controller.business.CondicaoClimaticaBusiness;
import br.senai.sc.controller.exception.BusinessException;
import br.senai.sc.model.CondicaoClimatica;
import br.senai.sc.util.SystemConstants;

/**
 * Responsável pelas funções que envolvem banco de dados da entidade
 * {@link CondicaoClimatica}.
 * 
 * @author Tiago
 */
@Stateless
// tive que colocar @Stateless, pois não estava funcionando os testes desta
// classe, nãe éra criada transação para a classe
public class CondicaoClimaticaCRUD implements Serializable {

	private static final long serialVersionUID = 1L;

	@PersistenceContext
	private EntityManager em;

	@Inject
	private Validator validator;

	@Inject
	private CondicaoClimaticaBusiness condicaoClimaticaBusiness;

	@Inject
	private Messages messages;

	/**
	 * Converte a lista de {@link ConstraintViolation} para uma lista de
	 * {@link BundleKey}.
	 * 
	 * @param constraints
	 * @return
	 */
	private void toBundleKeyList(
			Set<ConstraintViolation<CondicaoClimatica>> constraints) {

		for (ConstraintViolation<CondicaoClimatica> constraint : constraints) {
			messages.error(new BundleKey(
					SystemConstants.PATH_TO_COMMON_MESSAGES, constraint
							.getMessageTemplate()));
		}
	}

	/**
	 * Persiste os dados de uma {@link CondicaoClimatica}. Caso esteja salvando
	 * uma nova {@link CondicaoClimatica} valida as seguintes regras:
	 * 
	 * @param condicaoClimatica
	 * @return
	 * @throws BusinessException
	 *             Lançada caso houver alguma validação de negócio.
	 */
	public CondicaoClimatica salvar(CondicaoClimatica condicaoClimatica)
			throws BusinessException {

		if (condicaoClimatica == null) {
			throw new IllegalArgumentException(
					"Informando uma condição climática null para salvar.");
		}

		Set<ConstraintViolation<CondicaoClimatica>> constraints = validator
				.validate(condicaoClimatica);
		if (constraints.size() > 0) {
			toBundleKeyList(constraints);
			throw new BusinessException();
		}

		if (condicaoClimatica.getIdCondicaoClimatica() == null) {
			inserir(condicaoClimatica);
			return condicaoClimatica;
		}

		return atualizar(condicaoClimatica);
	}

	/**
	 * Efetua as regras de negócio para salvar uma nova
	 * {@link CondicaoClimatica}.
	 * 
	 * @param condicao
	 * @throws BusinessException
	 *             Lançada caso a {@link CondicaoClimatica} não seja válida.
	 */
	private void inserir(CondicaoClimatica condicao) throws BusinessException {

		if (!condicaoClimaticaBusiness.podeSalvarCondicaoClimatica(condicao)) {
			throw new BusinessException();
		}
		em.persist(condicao);
	}

	/**
	 * Efetua as regras de negócio para atualiza {@link CondicaoClimatica}.
	 * 
	 * @param condicaoClimatica
	 * @return {@link CondicaoClimatica} atualizada.
	 * @throws BusinessException
	 */
	private CondicaoClimatica atualizar(CondicaoClimatica condicaoClimatica)
			throws BusinessException {

		if (!condicaoClimaticaBusiness
				.podeEditarCondicaoClimatica(condicaoClimatica)) {
			throw new BusinessException();
		}
		return em.merge(condicaoClimatica);
	}

	/**
	 * Remove a {@link CondicaoClimatica} informada.
	 * 
	 * @param condicaoClimatica
	 * @throws BusinessException
	 *             Lançada se houver algum erro de validação.
	 */
	public void remover(CondicaoClimatica condicaoClimatica)
			throws BusinessException {

		if (condicaoClimatica == null) {
			throw new IllegalArgumentException(
					"Passou null para remover condição climática.");
		}

		if (!condicaoClimaticaBusiness
				.podeRemoverCondicaoClimatica(condicaoClimatica)) {
			throw new BusinessException();
		}

		em.remove(em.merge(condicaoClimatica)); // merge garante que a entidade
												// seja attached
	}

	/**
	 * @param idCondicaoClimatica
	 * @return {@link CondicaoClimatica} a partir do id informado.
	 * @throws IllegalArgumentException
	 *             Lançada caso informado null como parâmetro.
	 */
	public CondicaoClimatica findCondicaoClimatica(Integer idCondicaoClimatica) {

		if (idCondicaoClimatica == null) {
			throw new IllegalArgumentException(
					"Passado identificador null para procurar condição climática.");
		}
		return em.find(CondicaoClimatica.class, idCondicaoClimatica);
	}

	/**
	 * @return Todas as {@link CondicaoClimatica} cadastradas.
	 */
	public List<CondicaoClimatica> findCondicoesClimaticas() {
		return em.createNamedQuery(CondicaoClimatica.CONDICOES_CLIMATICAS,
				CondicaoClimatica.class).getResultList();
	}

}
